package com;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Comment;
import model.Gallery;
import model.Order;
import model.Product;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@ManagedBean
@SessionScoped
public class ShowProducts {

	protected static final Log logger = LogFactory.getLog(ShowProducts.class);

	@ManagedProperty(value = "#{productManager}")
	private ProductManager productManager;

	@ManagedProperty(value = "#{order}")
	private Order order;

	@ManagedProperty(value = "#{comment}")
	private Comment comment;

	private Product product;
	private String searchParam;
	private List<Product> search;
	private Set<Product> inCart = new HashSet<Product>();
	private List<Product> in = new ArrayList<Product>();
	private String emptyCartNotifier;
	private boolean isFormRendered;
	private BigDecimal subTotal;
	private boolean totalRendered;
	private List<Gallery> gallery;
	private List<Comment> comments;
	private static final String SC_COOKIE = "cartCookie";
	private static final String SC_TOTAL_PRICE = "cart_total";
	private static final String SC_SIZE = "cart_size";
	private static final String RECENT = "recent";
	private static int TWO_WEEKS = 24 * 3600 * 14;
	private Product[] recent = new Product[2];
	private int foundCount = 0;
	// private Cookie cookieIndicator = null;
	// if cookie value is null,that session is new
	private Cookie cookie;
	private String confirmationCode;
	private String viewId;

	// private Locale locale = FacesContext.getCurrentInstance().getViewRoot()
	// .getLocale();

	public ShowProducts() {
	}

	// constructor for testing
	public ShowProducts(Locale locale) {
	}

	// public Cookie getCookieIndicator() {
	// return cookieIndicator;
	// }
	//
	// public void setCookieIndicator(Cookie cookieIndicator) {
	// this.cookieIndicator = cookieIndicator;
	// }

	public int getFoundCount() {
		return foundCount;
	}

	public int getCommentsCount() {
		return getComments().size();
	}

	public Product[] getRecent() {
		String coo = extractSpecificCookie(RECENT);
		String cookies[] = coo.split("%");
		if (cookies != null) {
			for (int i = 0; i < cookies.length; i++) {
				if (cookies[i] != "") {
					// fix for Safari mixed cookies
					if (i < recent.length) {
						if (recent[i] == null) {
							Product p = getProductById(cookies[i]);
							recent[i] = p;
						}
					}
				}
			}
		}

		return recent;

	}

	public void setRecent() {

		boolean already = false;
		boolean nulls = false;

		for (int i = 0; i < recent.length; i++) {
			if (recent[i] == null) {
				nulls = true;
				break;
			}
			if (recent[i].getId().equals(product.getId())) {
				already = true;
			}
		}

		for (int i = 0; i < recent.length; i++) {
			if (nulls && !already) {
				if (recent[i] == null) {
					recent[i] = product;
					break;
				}
			}
			if (already) {
			}
			if (!already && !nulls) {
				System.arraycopy(recent, 0, recent, 1, recent.length - 1);
				recent[0] = product;
				break;
			}
		}

		persistCookiesForRecent();
	}

	private void persistCookiesForRecent() {
		HttpServletResponse httpServletResponse = (HttpServletResponse) FacesContext.getCurrentInstance()
				.getExternalContext().getResponse();

		String ids = "";

		for (Product prod : recent) {
			if (prod != null) {
				ids += prod.getId() + "%";
			}
		}

		Cookie cookie = new Cookie(RECENT, ids);
		cookie.setPath("/");
		cookie.setMaxAge(TWO_WEEKS);
		httpServletResponse.addCookie(cookie);
	}

	public Comment getComment() {
		return comment;
	}

	public void setComment(Comment comment) {
		this.comment = comment;
	}

	public List<Gallery> getGallery() {

		FacesContext context = FacesContext.getCurrentInstance();
		String id = context.getExternalContext().getRequestParameterMap().get("pname");

		if (id != null && !id.isEmpty()) {
			gallery = this.getProductManager().getGallery(id);
		}

		else if (product != null) {
			gallery = this.getProductManager().getGallery(product.getId());
		}

		else if (getProduct() != null) {
			gallery = this.productManager.getGallery(getProduct().getId());
		} else {
			logger.info("product wasn't found");
		}
		return gallery;
		// return
		// this.getProductManager().getGallery(this.getProduct().getName());
	}

	// TODO add hibernate one-to-many(one Product many Galleries) and
	// encapsulate within Product class
	public void setGallery(List<Gallery> gallery) {
		this.gallery = gallery;
		this.product.setGalleries(gallery);
	}

	public boolean isTotalRendered() {
		return totalRendered;
	}

	public void setTotalRendered(boolean totalRendered) {
		this.totalRendered = totalRendered;
	}

	public List<Product> getIn() {
		return new ArrayList<Product>(inCart);
	}

	public void setIn(Set<Product> in) {
		this.in = new ArrayList<Product>(inCart);
	}

	public BigDecimal getSubTotal() {
		HttpServletRequest httpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance()
				.getExternalContext().getRequest();
		Cookie[] cookies = httpServletRequest.getCookies();
		BigDecimal cookiesCartTotal = BigDecimal.ZERO;

		boolean present = false;

		if (cookies != null && this.cookie == null) {
			for (Cookie c : cookies) {
				if (SC_TOTAL_PRICE.equals(c.getName())) {
					if (!c.getValue().equals("null") && !c.getValue().isEmpty()) {
						cookiesCartTotal = new BigDecimal(c.getValue());
					}
				}
				if (SC_COOKIE.equals(c.getName())) {
					if (!c.getValue().isEmpty()) {
						present = true;
					}
				}
			}
		}
		if (inCart.isEmpty() && present || inCart.contains(null)) {
			return cookiesCartTotal;
		} else {
			subTotal = BigDecimal.ZERO;
			for (Product p : inCart) {
				subTotal = subTotal.add(p.getTotalPrice());
			}

		}
		HttpServletResponse httpServletResponse = (HttpServletResponse) FacesContext.getCurrentInstance()
				.getExternalContext().getResponse();
		Cookie cookie = new Cookie(SC_TOTAL_PRICE, String.valueOf(subTotal));
		cookie.setPath("/");
		cookie.setMaxAge(TWO_WEEKS);
		httpServletResponse.addCookie(cookie);

		persistCookies();

		return subTotal;
	}

	public void setSubTotal(BigDecimal subTotal) {
		this.subTotal = subTotal;
	}

	public boolean isFormRendered() {
		return isFormRendered;
	}

	public void setFormRendered(boolean isFormRendered) {
		this.isFormRendered = isFormRendered;
	}

	public int getCartSize() {
		HttpServletRequest httpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance()
				.getExternalContext().getRequest();

		// retrieve cart size from cookies
		Cookie[] cookies = httpServletRequest.getCookies();

		int cartSize = 0;
		boolean present = false;

		if (cookies != null && this.cookie == null) {
			for (Cookie c : cookies) {
				if (SC_SIZE.equals(c.getName())) {
					if (!c.getValue().isEmpty()) {
						cartSize = Integer.valueOf(c.getValue());
					}
				}
				if (SC_COOKIE.equals(c.getName())) {
					if (!c.getValue().isEmpty()) {
						present = true;
					}
				}
			}
		}
		// if (cookieIndicator != null) {
		//
		// if (cookieIndicator.getValue().isEmpty()) {
		// return cartSize;
		// }
		// }

		if (inCart.isEmpty() && present) {
			return cartSize;
		}

		return inCart.size();
	}

	public String getEmptyCartNotifier() {
		return emptyCartNotifier;
	}

	public void setEmptyCartNotifier(String emptyCartNotifier) {
		this.emptyCartNotifier = emptyCartNotifier;
	}

	public Set<Product> getInCart() {
		return inCart;
	}

	public void setInCart(Set<Product> inCart) {
		this.inCart = inCart;
	}

	public ProductManager getProductManager() {
		return productManager;
	}

	public void setProductManager(ProductManager productManager) {
		this.productManager = productManager;
	}

	public String getSearchParam() {
		return searchParam;
	}

	public void setSearchParam(String searchParam) {
		this.searchParam = searchParam;
	}

	public Order getOrder() {
		return order;
	}

	public void setOrder(Order order) {
		this.order = order;
	}

	public Product getProduct() {
		// take prodName parameter from GET response(bookmarkable URL)
		FacesContext context = FacesContext.getCurrentInstance();
		String id = context.getExternalContext().getRequestParameterMap().get("pname");
		if (id != null && !id.isEmpty()) {
			product = getProductById(id);
		}
		return product;
	}

	public void setProduct(Product product) {
		this.product = product;
	}

	public List<Product> getDecoys() {
		return this.getProductManager().getDecoys();
	}

	public List<Product> getRents() {
		return this.getProductManager().getRents();
	}

	public List<Product> getCamouflages() {
		return this.getProductManager().getCamouflages();
	}

	public List<Product> getSearch() {
		return search;
	}

	public void setSearch(List<Product> search) {
		this.search = search;
	}

	public String completeOrder() {
		try {
			order.setInfo(getPlainProduct());
			order.setProduct(inCart);
			this.getProductManager().save(order);
			try {
				Util.sendMail(order.getMail(), order);
			} catch (Exception e) {
				logger.error("mail can't be sent");
			}
			logger.info("order was completed:" + order.getExtraInfo());
			inCart.clear();

			persistCookies();
			order.resetForm();

		} catch (Exception e) {
			logger.debug("error occurred: " + e);
		}
		return "ordered";
	}

	public void removeOrder(ActionEvent e) {
		String productName = (String) e.getComponent().getAttributes().get("remove");
		Product p = getProductByName(productName);
		inCart.remove(p);
		Cookie cookie = persistCookies();
		emptyCartNotifier(cookie);
		totalRendered();
	}

	private Product getProductByName(String name) {
		for (Product p : inCart) {
			if (p.getName().equals(name)) {
				return p;
			}
		}
		return null;
	}

	public String buy() {

		String promo = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("promo");

		if (promo != null && !"".equals(promo)) {
			product = getProductById(promo);
		}

		if (product != null && !inCart.contains(product)) {
			inCart.add(product);
			int count = product.getCount();
			count++;
			product.setCount(count);
			Cookie cookie = persistCookies();
			emptyCartNotifier(cookie);
			totalRendered();
		}

		return "shoppingCart";
	}

	public Cookie persistCookies() {
		HttpServletResponse httpServletResponse = (HttpServletResponse) FacesContext.getCurrentInstance()
				.getExternalContext().getResponse();

		String ids = "";

		for (Product prod : inCart) {
			ids += prod.getId() + "~" + prod.getCount() + "@";
		}

		Cookie cookie = new Cookie(SC_COOKIE, ids);
		Cookie cookie2 = new Cookie(SC_SIZE, String.valueOf(inCart.size()));
		Cookie cookie3 = new Cookie(SC_TOTAL_PRICE, String.valueOf(subTotal));
		cookie3.setPath("/");
		cookie3.setMaxAge(TWO_WEEKS);
		httpServletResponse.addCookie(cookie3);
		cookie.setPath("/");
		cookie.setMaxAge(TWO_WEEKS);
		cookie2.setPath("/");
		cookie2.setMaxAge(TWO_WEEKS);

		httpServletResponse.addCookie(cookie);
		httpServletResponse.addCookie(cookie2);

		// setCookieIndicator(cookie);

		this.cookie = cookie;

		return cookie;

	}

	public String showCart() {
		emptyCartNotifier(new Cookie("init", " "));
		totalRendered();
		extractSCfromCookies();
		return "shoppingCart";
	}

	// TODO call this method on any page load in case map is empty
	private void extractSCfromCookies() {

		if (inCart.isEmpty()) {
			String cook = extractSpecificCookie(SC_COOKIE);

			String[] spl = cook.split("@");

			for (String s : spl) {
				if (StringUtils.isNotEmpty(s)) {
					Product p = getProductById(s.substring(0, s.indexOf("~")));
					Integer count = Integer.valueOf(s.substring(s.indexOf("~") + 1, s.length()));
					p.setCount(count);
					inCart.add(p);
				}
			}

		}
	}

	private String extractSpecificCookie(String cookieName) {
		HttpServletRequest httpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance()
				.getExternalContext().getRequest();
		Cookie[] cookies = httpServletRequest.getCookies();

		String cook = "";
		if (cookies != null) {
			for (Cookie c : cookies) {
				if (c.getName().equals(cookieName)) {
					cook = c.getValue();
				}
			}
		}
		return cook;
	}

	public void details() {
		// TODO impl as one-to-many mapping
		this.product.setGalleries(productManager.getGallery(this.product.getName()));
	}

	private String emptyCartNotifier(Cookie cookie) {

		// HttpServletRequest httpServletRequest = (HttpServletRequest)
		// FacesContext.getCurrentInstance().getExternalContext().getRequest();
		// Cookie[] cookies = httpServletRequest.getCookies();
		boolean isCookiePresent = false;
		// if (cookies != null) {
		// for (Cookie c : cookies) {
		// if (SC_COOKIE.equals(c.getName()) && (!c.getValue().isEmpty())) {
		// isCookiePresent = true;
		// }
		// }
		// }

		if (!cookie.getValue().isEmpty()) {
			isCookiePresent = true;
		}

		if (inCart.isEmpty() && (!isCookiePresent)) {
			FacesContext fc = FacesContext.getCurrentInstance();
			emptyCartNotifier = fc.getApplication().getResourceBundle(fc, "m").getString("empty_cart");
			isFormRendered = false;
		} else {
			emptyCartNotifier = "";
			isFormRendered = true;
		}
		return emptyCartNotifier;
	}

	public String continueShopping() {
		return "main";
	}

	private String getPlainProduct() {
		String plainProduct = "";

		for (Product p : inCart) {
			plainProduct = plainProduct + p.getName() + p.getCount();
		}
		return plainProduct;
	}

	public List<Product> search(ActionEvent e) {

		List<Product> objects = new ArrayList<Product>();

		objects = this.getProductManager().search(this.searchParam);

		this.search = objects;

		foundCount = search.size();

		return objects;
	}

	public Product getProductById(String id) {
		Product prod = this.getProductManager().getProductById(id);

		return prod;
	}

	private boolean totalRendered() {
		if (inCart.isEmpty() && extractSpecificCookie(SC_COOKIE).length() == 0) {
			totalRendered = false;
		} else {
			totalRendered = true;
		}
		return totalRendered;
	}

	// TODO implement comments saving with with method
	public void captchaSubmit(ActionEvent event) {
		FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Correct", "Correct");
		FacesContext.getCurrentInstance().addMessage(null, msg);
	}

	public void addComment() {

		comment.setProductName(product.getName());
		comment.setPostDate(new Date());

		this.getProductManager().save(comment);

		comment.resetForm();

	}

	public void setComments(List<Comment> comments) {
		this.comments = comments;
	}

	public List<Comment> getComments() {

		if (product != null) {
			comments = this.productManager.getComments(product.getName());
		} else if (getProduct() != null) {
			comments = this.productManager.getComments(getProduct().getName());
		} else {
			logger.info("product wasn't found");
		}

		return comments;
	}

	public String getConfirmationCode() {
		String username = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("username");
		confirmationCode = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("code");
		if (productManager.confirmUser(username, confirmationCode) > 0) {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "registration confirmed OK",
					"registration confirmed OK");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return "OK";
		} else {
			FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "registration couldn't be confirmed",
					"registration couldn't be confirmed");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return "FAIL";
		}

	}

	public void setConfirmationCode(String confirmationCode) {
		this.confirmationCode = confirmationCode;
	}

	public String getViewId() {
		viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
		return viewId;
	}

	public void setViewId(String viewId) {
		this.viewId = viewId;
	}

}
